﻿////-----------------------------------------------------------------------
//// <copyright company="www.3WayWebdesign.de">
//// Permission is hereby granted, free of charge, to any person obtaining
//// a copy of this software and associated documentation files (the
//// "Software"), to deal in the Software without restriction, including
//// without limitation the rights to use, copy, modify, merge, publish,
//// distribute, sublicense, and/or sell copies of the Software, and to
//// permit persons to whom the Software is furnished to do so, subject to
//// the following conditions:
////
//// The above copyright notice and this permission notice shall be
//// included in all copies or substantial portions of the Software.
//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
//// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
//// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
//// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//// </copyright>
////
//// <author>Michael Morbach</author>
//// <email>Michael@3waywebdesign.de</email>
//// <web>http://www.3waywebdesign.de</web>
////-----------------------------------------------------------------------

using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using GalaSoft.MvvmLight;
using Microsoft.Practices.Unity;

namespace Tww.MAF.MAFEngine.Navigator
{
    public class MAFBrowser : ObservableObject, IBrowser
    {
        #region  - Felder (privat) -

        private INavigator _currentNavigator;
        private ObservableCollection<INavigator> _internalNavigatorList;
        private ReadOnlyObservableCollection<INavigator> _navigatorList;

        #endregion

        #region  - Konstruktoren -

        /// <summary>
        /// Initializes a new instance of the <see cref="MAFBrowser"/> class.
        /// </summary>
        /// <param name="container">The container.</param>
        public MAFBrowser(IUnityContainer container)
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }

            Container = container;
            NavigatorFactory = Container.Resolve<INavigatorFactory>();
        }

        #endregion

        #region  - Indexer und Eigenschaften (privat) -

        /// <summary>
        /// Gets or sets the container.
        /// </summary>
        /// <value>
        /// The container.
        /// </value>
        private IUnityContainer Container { get; set; }

        protected ObservableCollection<INavigator> InternalNavigatorList
        {
            get { return _internalNavigatorList ?? (_internalNavigatorList = CreateInternalNavigatorList()); }
        }

        #endregion

        #region  - IBrowser Members -

        /// <summary>
        /// Gets the current navigator.
        /// </summary>
        /// <value>
        /// The current navigator.
        /// </value>
        public INavigator CurrentNavigator
        {
            get { return _currentNavigator; }
            private set
            {
                _currentNavigator = value;
                RaisePropertyChanged(() => CurrentNavigator);
            }
        }

        public void AddNavigator(INavigator navigator)
        {
            InternalNavigatorList.Add(navigator);
        }

        /// <summary>
        /// Gets or sets the navigator list.
        /// </summary>
        /// <value>
        /// The navigator list.
        /// </value>
        public ReadOnlyObservableCollection<INavigator> NavigatorList
        {
            get
            {
                return _navigatorList ??
                       (_navigatorList = new ReadOnlyObservableCollection<INavigator>(InternalNavigatorList));
            }
        }


        /// <summary>
        /// Navigates to the specified destination.
        /// </summary>
        /// <param name="navigator">The navigator.</param>
        /// <param name="destination">The destination.</param>
        /// <param name="context">The context.</param>
        /// <param name="navigationCallback">The navigation callback.</param>
        public void Navigate(INavigator navigator, Uri destination, NavigationContext context,
            Action<NavigationResult> navigationCallback)
        {
            navigator.Navigate(destination, context, navigationCallback);
        }

        /// <summary>
        /// Navigates to the specified destination inside a new Navigator
        /// </summary>
        /// <param name="destination">The destination.</param>
        /// <param name="context">The context.</param>
        /// <param name="navigationCallback">The navigation callback.</param>
        public void NavigateInNewNavigator(Uri destination, NavigationContext context,
            Action<NavigationResult> navigationCallback)
        {
            //INavigator newNavigator = CreateNewNavigator();
            //newNavigator.Navigate(destination, context, navigationCallback);
        }

        /// <summary>
        /// Navigates to the specified destination.
        /// </summary>
        /// <param name="navigatorId">The navigator identifier.</param>
        /// <param name="destination">The destination.</param>
        /// <param name="context">The context.</param>
        /// <param name="navigationCallback">The navigation callback.</param>
        public void Navigate(Guid navigatorId, Uri destination, NavigationContext context,
            Action<NavigationResult> navigationCallback)
        {
            INavigator navigator = NavigatorList.First(n => n.NavigatorId == navigatorId);
            Navigate(navigator, destination, context, navigationCallback);
        }

        public event NotifyCollectionChangedEventHandler CollectionChanged
        {
            add { _internalNavigatorList.CollectionChanged += value; }
            remove { _internalNavigatorList.CollectionChanged -= value; }
        }

        /// <summary>
        /// Gets the navigator factory.
        /// </summary>
        /// <value>
        /// The navigator factory.
        /// </value>
        public INavigatorFactory NavigatorFactory { get; private set; }

        #endregion

        #region  - Methoden (öffentlich) -

        public void RemoveNavigator(INavigator navigator)
        {
            InternalNavigatorList.Remove(navigator);
        }

        #endregion

        #region  - Methoden (privat) -

        protected virtual ObservableCollection<INavigator> CreateInternalNavigatorList()
        {
            var internalList = new ObservableCollection<INavigator>();
            internalList.CollectionChanged += NavigatorListOnCollectionChanged;
            return internalList;
        }

        private void RegisterNavigator(INavigator navigator)
        {
            navigator.NavigatorClosed += NavigatorOnNavigatorClosed;
        }

        private void UnregisterNavigator(INavigator navigator)
        {
            navigator.NavigatorClosed -= NavigatorOnNavigatorClosed;
        }

        private void NavigatorOnNavigatorClosed(object sender, EventArgs eventArgs)
        {
            RemoveNavigator(sender as INavigator);
        }

        private void NavigatorListOnCollectionChanged(object sender,
            NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
        {
            switch (notifyCollectionChangedEventArgs.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    foreach (INavigator oldItem in notifyCollectionChangedEventArgs.NewItems)
                    {
                        RegisterNavigator(oldItem);
                    }
                    break;
                case NotifyCollectionChangedAction.Remove:
                    foreach (INavigator oldItem in notifyCollectionChangedEventArgs.OldItems)
                    {
                        UnregisterNavigator(oldItem);
                    }
                    break;
            }
        }

        #endregion
    }
}